;function isObject(value) {
    var type = typeof value
    return value != null && (type == 'object' || type == 'function')
}

var _ = {
    debounce:
        function (func, wait, options) {
            var lastArgs,
                lastThis,
                maxWait,
                result,
                timerId,
                lastCallTime

            var lastInvokeTime = 0
            var leading = false
            var maxing = false
            var trailing = true

            var useRAF = (!wait && wait !== 0 && typeof window.requestAnimationFrame === 'function')

            if (typeof func != 'function') {
                throw new TypeError('Expected a function')
            }
            wait = +wait || 0
            if (isObject(options)) {
                leading = !!options.leading
                maxing = 'maxWait' in options
                maxWait = maxing ? Math.max(+options.maxWait || 0, wait) : maxWait
                trailing = 'trailing' in options ? !!options.trailing : trailing
            }

            function invokeFunc(time) {
                var args = lastArgs
                var thisArg = lastThis

                lastArgs = lastThis = undefined
                lastInvokeTime = time
                result = func.apply(thisArg, args)
                return result
            }

            function startTimer(pendingFunc, wait) {
                if (useRAF) {
                    return window.requestAnimationFrame(pendingFunc)
                }
                return setTimeout(pendingFunc, wait)
            }

            function cancelTimer(id) {
                if (useRAF) {
                    return window.cancelAnimationFrame(id)
                }
                clearTimeout(id)
            }

            function leadingEdge(time) {
                // Reset any `maxWait` timer.
                lastInvokeTime = time
                // Start the timer for the trailing edge.
                timerId = startTimer(timerExpired, wait)
                // Invoke the leading edge.
                return leading ? invokeFunc(time) : result
            }

            function remainingWait(time) {
                var timeSinceLastCall = time - lastCallTime
                var timeSinceLastInvoke = time - lastInvokeTime
                var timeWaiting = wait - timeSinceLastCall

                return maxing
                    ? Math.min(timeWaiting, maxWait - timeSinceLastInvoke)
                    : timeWaiting
            }

            function shouldInvoke(time) {
                var timeSinceLastCall = time - lastCallTime
                var timeSinceLastInvoke = time - lastInvokeTime

                // Either this is the first call, activity has stopped and we're at the
                // trailing edge, the system time has gone backwards and we're treating
                // it as the trailing edge, or we've hit the `maxWait` limit.
                return (lastCallTime === undefined || (timeSinceLastCall >= wait) ||
                    (timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait))
            }

            function timerExpired() {
                var time = Date.now()
                if (shouldInvoke(time)) {
                    return trailingEdge(time)
                }
                // Restart the timer.
                timerId = startTimer(timerExpired, remainingWait(time))
            }

            function trailingEdge(time) {
                timerId = undefined

                // Only invoke if we have `lastArgs` which means `func` has been
                // debounced at least once.
                if (trailing && lastArgs) {
                    return invokeFunc(time)
                }
                lastArgs = lastThis = undefined
                return result
            }

            function cancel() {
                if (timerId !== undefined) {
                    cancelTimer(timerId)
                }
                lastInvokeTime = 0
                lastArgs = lastCallTime = lastThis = timerId = undefined
            }

            function flush() {
                return timerId === undefined ? result : trailingEdge(Date.now())
            }

            function pending() {
                return timerId !== undefined
            }

            function debounced() {
                var time = Date.now()
                var isInvoking = shouldInvoke(time)

                lastArgs = arguments;
                lastThis = this
                lastCallTime = time

                if (isInvoking) {
                    if (timerId === undefined) {
                        return leadingEdge(lastCallTime)
                    }
                    if (maxing) {
                        // Handle invocations in a tight loop.
                        timerId = startTimer(timerExpired, wait)
                        return invokeFunc(lastCallTime)
                    }
                }
                if (timerId === undefined) {
                    timerId = startTimer(timerExpired, wait)
                }
                return result
            }
            debounced.cancel = cancel
            debounced.flush = flush
            debounced.pending = pending
            return debounced
        }

};
